from typing import List

from algorithm.abstract_algorithm import AbstractAlgorithm
from algorithm.jiareqi_for_emr_online import JiareqiFactory
from common.sagemaker_runner_framework import SagemakerFactory
from common.spark_runner_framework import SparkFrameWorkFactory
from common.source_reader import *
from constants import *

frameworks_factor = {
    "spark": SparkFrameWorkFactory(),
    "sagemaker": SagemakerFactory()
}

algorithms_factor = {
    "jiareqi_http": JiareqiFactory()
}


def generate_jobs(job_json) -> List[AbstractAlgorithm]:
    jobs: List[AbstractAlgorithm] = []
    for job_param in job_json:
        name = job_param[AlgorithmsParam.NAME]
        jobs.append(algorithms_factor[name].build_algorithm(job_param))
    return jobs


def generate_job_params(algorithms: List[AbstractAlgorithm]) -> dict:
    table_params = {}
    for a in algorithms:
        table = a.config.table().value

        if table not in table_params:
            table_params[table] = {}

        p = table_params[table]

        materials = a.config.input_params['materials'].split(',') if 'materials' in a.config.input_params else []
        materials_except = a.config.input_params['materials_except'].split(
            ',') if 'materials_except' in a.config.input_params else []
        model = a.config.input_params['model'].split(',') if 'model' in a.config.input_params else []
        model_except = a.config.input_params['model_except'].split(
            ',') if 'model_except' in a.config.input_params else []
        sn = a.config.input_params['sn'].split(',') if 'sn' in a.config.input_params else []
        sn_except = a.config.input_params['sn_except'].split(',') if 'sn_except' in a.config.input_params else []

        p['columns'] = [] if 'columns' not in p else list(set(p['columns'].extend(
            a.config.select_columns())))
        p['max_day'] = 0 if 'max_day' not in p else max(p['max_day'], a.config.select_days())
        p['materials'] = [] if 'materials' not in p else list(set(p['materials'].extend(materials)))
        p['materials_except'] = [] if 'materials_except' not in p else list(
            set(p['materials_except'].extend(materials_except)))
        p['model'] = [] if 'model' not in p else list(set(p['model'].extend(model)))
        p['model_except'] = [] if 'model_except' not in p else list(set(p['model_except'].extend(model_except)))
        p['sn'] = [] if 'sn' not in p else list(set(p['sn'].extend(sn)))
        p['sn_except'] = [] if 'sn_except' not in p else list(set(p['sn_except'].extend(sn_except)))
    return table_params


def run(js):
    # 解析算法参数
    algorithm_params = js['algorithms']
    # 根据算法参数创建算法实体类
    algorithms = generate_jobs(algorithm_params)

    # 寻找算法中需要的数据字段和数据时间范围

    # 任务参数，例如 framework类型，日期，物料等
    common_params = js['common']

    # 根据framework构建选择框架
    framework = frameworks_factor[common_params[Source.FRAMEWORK]].create(common_params)

    job_params = generate_job_params(algorithms)
    # 根据每一个任务参数创建reader
    reader = create_reader(common_params, job_params)

    # 读取数据
    data = framework.get_source(reader)

    # 过滤数据
    data = framework.filter(data)

    # 运行每一个算法并写出数据
    for algorithm in algorithms:
        # try:
        one_data = framework.detect(data, algorithm)
        framework.write(one_data)
        # except Exception as e:
        #     print("Error", algorithm)
        #     print(Exception)
